// =============================1.string类型===================================

// 定义类型不赋值
let userName: string
// userName = 123//不能将类型“number”分配给类型“string”。

// 定义类型并赋值
let userHopy: string = "篮球"
// userHopy = true//不能将类型“boolean”分配给类型“string”。

//定义变量并赋值（TS类型自动推断）
let userSex = "男"
// userSex = {}//不能将类型“{}”分配给类型“string”。


// ============================2.number类型=====================================
let userAge = 20
// userAge = {}//不能将类型“{}”分配给类型“number”。
let subjectNumber:number=1000


// ============================3.bool类型=======================================
let isShow: boolean
isShow = true
// isShow = 123//不能将类型“number”分配给类型“boolean”。


// =============================4.字面量类型=====================================
// 变量的值必须和自定义变量类型值一致
// 也可以使用字面量去指定变量的类型，通过字面量可以确定变量的取值范围

// 定义字面量类型
let subName: "web"
// subName = 123//不能将类型“123”分配给类型“"web"”。
subName = "web"


// 字面量配合联合类型('|')使用
let color: "red" | "green" | "blue"
color = "green"
color = "blue"


//=================================5.any 任何类型 没有类型校验====================
// 如果变量声明了但是没有设置类型和赋值 默认类型就是any
let p1
p1 = 123
p1 = "你好"
p1 = {}
p1 = [1,2,3]

// 可以将any类型的数据直接赋值给其他变量 不够安全
let p2 = 123
p2 = p1
console.log('p2:',p2)


// ====================6.unknown 未知类型 安全的any类型===========================
//不能将类型“unknown”随意分配给其他类型。
let p3: unknown
p3 = 123
p3 = []

let p4 = 123
// p4 = p3//不能将类型“unknown”分配给类型“number”。

// 可以通过类型断言赋值给其他变量
p4 = p3 as number //当p3是number类型的时候赋值给p4
p4 = <number>p3 //当p3是number类型的时候赋值给p4


// ==============7.void 空值(undefined) 没有任何类型 常用于没有返回值的方法=========
let p5: void
// p5 = 123//不能将类型“number”分配给类型“void”。
p5 = undefined
// p5 = null//不能将类型“null”分配给类型“void”。

// void可以用于函数的返回值 表示没有返回值结果
function getUser():void { 
    console.log(111)
}
getUser()



// ===========================8.never 永远不会有值的一种类型=======================
//不能将类型“undefined”分配给类型“never”。
let p6: never
// p6 = undefined//不能将类型“undefined”分配给类型“never”。

// 一个从来不会有返回值的函数,即死循环
function xunhuan():never { 
    while (true) { }
}

// 一个总是会抛出错误的函数
function getError():never { 
    throw new Error('我是错误信息')
}


// never 和 void 的差异
// void 表示没有任何类型，never 表示永远不存在的值的类型。
// 返回never的函数必须存在无法达到的终点


// ===========================9.object 语法：object | {}==========================
let p7: object
// p7 = 123//不能将类型“number”分配给类型“object”。
p7 = {id:11,name:"李四"}

let p8: {}
p8 = { hopy: "篮球" }

let p9: { sex: string, age: number,[propName:string]:any }
p9 = {sex:"女",age:20,work:"it"}


// =========================10.array 语法：类型[] | Array<类型>====================
let p10: number[]
p10 = [1, 2, 3, 4]

let p11:string[]
p11 = ['1','2','3']

let p12: Array<number>
p12 = [1, 2]

let p13: any[]


// ===============11.元组tuple 固定长度的数组 语法：[类型，类型.....]================
let p14: [string, number, {id:string}]
p14 = ['12', 34, {id:'11'}]



// ===================12.枚举类型 语法：enum value{v1,v2}==========================
// 联合类型写法 不清楚 数字具体是什么意思？
let orderStatus: 1 | 2 | 3 
orderStatus = 1


let codes: 203|503|101

// 使用枚举优化解决(立即执行函数)
enum statusCode { 
    "success"=200,//0  左侧是对右侧取值的描述（字符串）
    "失败"=500,//1
    "请求中"=100//2
}

// console.log(statusCode)

let code: statusCode
code = statusCode.success 
console.log(code)//500


// ========================13.类型别名 语法： type value:==========================

// 单个写比较麻烦 代码冗余
let p15:{id:number,name:string}
let p16:{id:number,name:string}
let p17: { id: number, name: string }

// 使用类型别名 实现代码复用  左侧是类型名称  右侧类型（不是具体的变量值）
type objType = { id: number, name: string,hopy:string }

let p18: objType
// p18 = {}//类型“{}”缺少类型“objType”中的以下属性: id, name
p18 = {id:1,name:"李四",hopy:"篮球"}



// ========================14.类型断言 语法： prop as type | <type>prop============
// 有些情况下，变量的类型对于我们来说是很明确，但是TS编译器却并不清楚，
// 此时，可以通过类型断言来告诉编译器变量的类型
let p19: unknown
p19 = 12
p19 = "hello"

let p20 = 123
// p20 = p19 //直接赋值失败
p20 = p19 as number
p20 = <number>p19
if (typeof(p19) == "number") {
    p20 = p19
}



// ========================15.函数  关心其参数类型和返回值类型=======================


// 内置类型推断
// function f1(name) {
//     console.log('用户姓名是：'+name)
// }

// f1("李四")


// function f2(name:string,age:number):void {
//     console.log('用户姓名是：'+name)
// }

// f2("李四", 20)


function f3(name:string,age:number) {
    return name
}

f3("李四",20)




// =======================16.接口 interface 语法：interface 接口名称 {}======================
// 接口可以去限制一个对象的结构，对象只有包含接口中定义的所有属性和方法时才能匹配接口。
let p21: { name: string, age: number }
// p21 = {}

// 定义接口规范对象数据内容（项目中常用）
interface userType { 
    id: number;
    name: string;
    [propName: string]: any;
}

let p22: userType
p22 = {id:11,name:"鲁班",age:20}


// 项目实际应用：
let data = {
    list: [] as userType[],
    all:<userType[]>[]
}

// let listq:userType = []




// =========================17.泛型 <T>============================================
// 定义一个函数或类时，有些情况下无法确定其中要使用的具体类型（返回值、参数、属性的类型不能确定）


// fn2(null)//类型受限制

//any不安全 


//泛型灵活        



